The shiny app takes ingredient and diet input and gives the recipe title, ingredients and url.
diets <- c("None", "Pescatarian" ,"Vegetarian", "Vegan", "Gluten Free",
"Dairy Free", "Soy Free", "Pork Free")
ui <- fluidPage(
title = "What's in the pantry?",
titlePanel("What's in my pantry?"),
textInput("ingredient",
"What do you have? Separate ingredients with a comma",
placeholder = "e.g., tomato"), # ingredient input
selectInput("diet", "dietary restrictions?",
choices = diets), # diet input
sidebarLayout(
sidebarPanel(
tableOutput("title"), #gives title
tableOutput("ingtable"), #gives the ingredients
actionButton("button", "Get recipe!"),
actionButton("reset", "New search?")
),
mainPanel(
h3("If you want another recipe, click on the 'Get Recipe!' button."),
h3("If you want to change the ingredients and/or the diet,
press the 'New search?' button"),
uiOutput("link")
)
)
)This is the code for the UI part. There’s two user inputs:
ingredients - text input
diet - select input (choices are shown in the “diets” vector)
The code gives two table outputs (title and ingredients), a URL output to the recipe. There are also two action buttons, one that retrieves the ingredients and another that resets the app.
This is how the app looks prior to any input added.
server <- function(input, output, session) {
food <- reactive({
strsplit(input$ingredient, ",\\s*")[[1]] })
# creates input into a character vector
restr <- reactive({
strsplit(input$diet, ",\\s*")[[1]] })
# creates input into a character vector
n <- reactiveVal(0)
recipe <- reactive({
get_info(food(), restr())
})
observeEvent(input$button, { #pulls up the recipe
n(n() + 1) #for the button to update
output$title <- renderTable({ #renders the title of the recipe
validate( # error message if recipes have been run through
need(n() <= length(recipe()), "Ran out of food :-(")
)
df <- data.frame(recipe()[[n()]][[1]])
colnames(df) <- c("Title")
return(df)
})
output$link <- renderUI({ # gives the url to the recipe
validate(
need(n() <= length(recipe()), "Ran out of food :-(")
)
url <- a("Link to the recipe",
href = recipe()[[n()]][[2]],
target = "_blank")
tagList(url)
})
output$ingtable <- renderTable({ #renders ingredients of the recipe
validate(
need(n() <= length(recipe()), "Ran out of food :-(")
)
df2 <- matrix(recipe()[[n()]][[3]], ncol = 1)
colnames(df2) <- c("Ingredients")
return(df2)
})
})
observeEvent(input$reset, { # reloads the entire app
session$reload()
})
}The food and diet inputs must first be converted into character vectors for the function to read them.
Then I created a variable that keeps track of which recipe the function is on with each button press (the variable ‘n’). This also pulls each following recipe, because the function initially pulls all recipes that match its query.
Then I render two tables and an URL. The rendering is in table format because it looks nicer than plain text, given the data type. The URL being an already usable link is for easier access to the recipe.
The reset button reloads the entire session, when a person wants to change the ingredients and/or the dietary restriction.
Finally, the validate( ) function is mainly to display a more informative error message, when n becomes larger than the length of the recipe. Or in other words, when all recipes have been cycled through.
food <- c("chickpeas", "tomato")
recipes <- PantryPackage::get_info(food, "Vegan")The function pulls recipes from a food API and puts them into a list. The function first calls for recipes that contain the requested ingredients and then goes through each and puts the recipes in a list that match the dietary requirement. This is the backbone of the shiny app.
This is what the output of recipe title, ingredients and url looks like with the input of “chicken” and “potato” and no dietary restriction. If you press on the “Get Recipe!” button, the next recipe is pulled. (See below the next pulled recipe)
Once you run out of recipes, this is what is displayed.
PantryPackage::whatsinmypantry()This is the function that runs the Shiny app. It will open a new browser window with the app.